#pragma once

#include <boost/random.hpp>

#include "ParticleEmitter.h"
#include "PointZone.h"




namespace math
{
   /**
    * @brief   A ParticleEmitter that emits in a random direction using a random velocity.
    *
    * Both position and velocity are distributed uniform.
    */
   template
   <
      typename float_t
   >
   class RandomParticleEmitter : public ParticleEmitter
   {
   public:

      typedef boost::mt19937                                rng;
      typedef boost::uniform_real<float_t>                  distribution;
      typedef boost::variate_generator<rng&,distribution>   generator;

   private:

      /// This defines the algorithm that is used to obtain pseudo random-numbers
      rng            m_algorithm;

      /// This defines the distribution for the velocity amount
      distribution   m_amountDist;

      /// This defines the distribution for the velocity direction (usually [-1,1] for every axis)
      distribution   m_directionDist;

      /// This is the generator that packs algorithm and distribution together
      generator      m_amountGen;
      generator      m_dirGen;

   public:

      RandomParticleEmitter(int tank, float_t rate, const vector2<float_t>& velocity, const ZonePtr& zone = ZonePtr(new PointZone))
         : ParticleEmitter(tank, rate, velocity)
         , m_amountDist(velocity.x, velocity.y)
         , m_directionDist(-1, 1)
         , m_amountGen(m_algorithm, m_amountDist)
         , m_dirGen(m_algorithm, m_directionDist)
      {}

      virtual ~RandomParticleEmitter()
      {}



      /**
       * Set the minimum and maximum velocity that is applied to a particle.
       */
      virtual void setVelocity(const vector2<float_t>& velocity)
      {
         ParticleEmitter::setVelocity(velocity);
         m_amountDist = distribution(velocity.x, velocity.y);
         m_amountGen  = generator(m_algorithm, m_amountDist);
      }



      /**
       * Generate a velocity for a new particle.
       * The velocity is uniformly distributed between (min,max) velocity and points at
       * a uniformly distributed random 3-dimensional direction.
       */
      virtual vector3_t generateVelocity() const
      {
         // Create a 3-dimensional vector that points at a random direction.
         // Simply create a random number in [-1,1] for each axis and normalize the vector
         // After that multiply it by the actual velocity amount, retrieved by another generator.
         vector3_t dir(m_dirGen(), m_dirGen(), m_dirGen());
         dir.norm();
         return dir * m_amountGen();
      }

      /**
       * Generate a position for a new particle.
       * The position is uniformly distributed in the Zone's area.
       */
      virtual vector3_t generatePosition() const
      {
         // Pick a random position within the Zone
         // This totally depends on the zone, which is why the Zone has the code
         return zone()->generatePosition();
      }
   };
   ///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
